const fs = require('fs')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const path = require('path')
const babel = require('@babel/core')


const getModuleInfo = (file) => {
    const body = fs.readFileSync(file, 'utf-8')
    const ast = parser.parse(body, {
        sourceType: 'module'  // 告诉babel我们要解析的是ESModule模块
    })

    const deps = {}  // 依赖收集  {'./add.js':'./src/add.js'}
    traverse(ast, {
        ImportDeclaration({ node }) {
            const dirname = path.dirname(file)
            const abspath = './' + path.join(dirname, node.source.value)
            deps[node.source.value] = abspath
        }
    })

    // 代码转换
    const { code } = babel.transformFromAst(ast, null, {
        presets: ['@babel/preset-env']
    })

    const moduleInfo = { file, deps, code }
    return moduleInfo

}

// 递归获取依赖
const parseModules = (file) => {  //  尾递归
    const entry = getModuleInfo(file)
    const temp = [entry]

    for (let i = 0; i < temp.length; i++) {
        const deps = temp[i].deps
        if (deps) {
            for (const key in deps) {  // './add.js'
                if (deps.hasOwnProperty(key)) {
                    temp.push(getModuleInfo(deps[key]))
                }
            }
        }
    }

    // console.log(temp);
    const depsGraph = {}
    temp.forEach((item) => {
        depsGraph[item.file] = {
            deps: item.deps,
            code: item.code
        }
    })
    // console.log(depsGraph);
    return depsGraph

}

const bundle = (file) => {
    const depsGraph = JSON.stringify(parseModules(file))

    return `(function (graph) {
    function require(file) {
      function absRequire(relPath) {
        return require(graph[file].deps[relPath])
      }
      var exports = {};

      (function (require, exports, code) {
        eval(code)
      })(absRequire, exports, graph[file].code)

      return exports
    }
    require('${file}')
  })(${depsGraph})`
}

const content = bundle('./src/index.js')
// console.log(content);
fs.mkdirSync('./dist')
fs.writeFileSync('./dist/main.js', content)